/**
 * 
 */
package org.metaverse.restful;

import java.io.StringWriter;
import java.util.Date;

import org.metaverse.warehouse.rdf.Converter;
import org.openrdf.model.BNode;
import org.openrdf.model.Literal;
import org.openrdf.model.URI;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.impl.ValueFactoryImpl;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.XMLSchema;
import org.openrdf.rio.RDFFormat;
import org.openrdf.rio.RDFHandlerException;
import org.openrdf.rio.RDFWriter;
import org.openrdf.rio.Rio;

/**
 * @author vjache
 *
 */
public class SemanticException extends Exception {
private static final long serialVersionUID = -2800929583704231981L;

	private static final String ERR_NS = "http://www.metaverse.org/ontology/sys/err#";
	
	private static final URI ERR_CTX = new URIImpl(ERR_NS);
	private static final URI ERR_CLS = new URIImpl(ERR_NS+"Exception");
	private static final URI ERR_CODE_PRED = new URIImpl(ERR_NS+"hasCode");
	private static final URI ERR_MSG_PRED = new URIImpl(ERR_NS+"hasMessage");
	private static final URI ERR_TS_PRED = new URIImpl(ERR_NS+"hasTimeStamp");

	public enum ErrorCode
	{
		BadJsonSyntaxError,
		BadConstraintError,
		WarehouseError,
		FetcherOutOfServiceError,
		FetcherError,
		UploaderOutOfServiceError,
		UploaderError,
		UnInterprettedError
	}
	private final ErrorCode _code;
	private final String _message;
	private final RDFFormat _format;


	/**
	 * 
	 */
	public SemanticException(RDFFormat aFormat, ErrorCode aCode) 
	{
		this(aFormat,aCode,(String)null);
	}
	
	public RDFFormat getPreferredRdfFormat()
	{
		return _format;
	}
	/**
	 * 
	 */
	public SemanticException(RDFFormat aFormat,ErrorCode aCode, Throwable aThrowable) 
	{
		this(aFormat,aCode,aThrowable.getMessage());
	}
	/**
	 * 
	 */
	public SemanticException(RDFFormat aFormat,Throwable aThrowable) 
	{
		this(aFormat,ErrorCode.UnInterprettedError,aThrowable.getMessage());
	}
	/**
	 * 
	 */
	public SemanticException(RDFFormat aFormat, ErrorCode aCode,String aHumanReadableMessage) 
	{
		_code = aCode;
		_message = aHumanReadableMessage;
		_format = aFormat;
	}
	
	public String toString(RDFFormat aFormat) throws RDFHandlerException {
		
		ValueFactoryImpl vf = new ValueFactoryImpl();
		
		StringWriter sw = new StringWriter();
		RDFWriter wrt = Rio.createWriter(aFormat, sw);
		wrt.startRDF();
		wrt.handleNamespace("xsd", XMLSchema.NAMESPACE);
		wrt.handleNamespace("mv", ERR_NS);
		BNode sbj = vf.createBNode("error");
		wrt.handleStatement(vf.createStatement(sbj, RDF.TYPE, ERR_CLS, ERR_CTX));
		Literal codeLit = vf.createLiteral(_code.name());
		wrt.handleStatement(vf.createStatement(sbj, ERR_CODE_PRED, codeLit,ERR_CTX));
		Literal tsLit = Converter.valueOf(new Date(), vf);
		wrt.handleStatement(vf.createStatement(sbj, ERR_TS_PRED, tsLit,ERR_CTX));
		if(_message!=null)
		{
			Literal msgLit = vf.createLiteral(_message);
			wrt.handleStatement(vf.createStatement(sbj, ERR_MSG_PRED, msgLit,ERR_CTX));
		}
		wrt.endRDF();
		return sw.toString();
	}
	
	@Override
	public String toString() {
		try {
			return toString(_format);
		} catch (RDFHandlerException e) {
			return e.getMessage();
		}
	}
}
